package br.com.sgi.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import br.com.sgi.autentication.UsuarioLogado;
import br.com.sgi.dao.MembroDao;
import br.com.sgi.enuns.OperacaoPesquisaEnum;
import br.com.sgi.model.Membro;
import br.com.sgi.service.MembroService;
import br.com.sgi.service.VisitanteService;
import br.com.sgi.util.DateUtil;
import br.com.sgi.vo.MembroVo;
import br.com.sgi.vo.ParametroPesquisa;

@Service("membroService")
public class MembroServiceImpl implements MembroService {

	@Autowired
	private MembroDao membroDao;

	@Autowired
	private VisitanteService visitanteService;

	/**
	 * entityManager
	 */
	@PersistenceContext
	private EntityManager entityManager;

	public void atualizar(Membro membro) {
		membroDao.update(membro);
	}
	
	@Override
	public List<MembroVo> buscarMembrosPorIgrejaComEmail(Long coIgreja){
		Map<String, Object> params = new HashMap<String, Object>();

		params.put("coSistema", UsuarioLogado.getCoSistema());

		StringBuffer sql = new StringBuffer();
		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( m )  FROM Membro m");
		sql.append("\n join m.igrejaPertence i ");
		sql.append("\n join i.sistema s ");
		sql.append("\n WHERE s.coSeqSistema =:coSistema ");

		if (coIgreja != null) {
			params.put("coIgrejaPertence", coIgreja);
			sql.append("\n AND i.coSeqIgreja =:coIgrejaPertence ");
		}else{
			params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
			params.put("username", UsuarioLogado.getCoUsuario());
			
			sql
			.append(" \n AND (m.igrejaPertence.coSeqIgreja = :coIgreja "
					+ "	OR i.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");
		}
			

		sql.append("\n AND m.email != '' ");
		sql.append("\n AND m.inativo = 'N' ");
		
		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}
		return consulta.getResultList();
		
	}

	@Override
	public List<MembroVo> buscaDinamicaMembro(List<ParametroPesquisa> parametros, Long coIgreja,
			String status) {
		Map<String, Object> params = new HashMap<String, Object>();

		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		params.put("coSistema", UsuarioLogado.getCoSistema());

		StringBuffer sql = new StringBuffer();
		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( m )  FROM Membro m");
		sql.append("\n join m.igrejaPertence i ");
		sql.append("\n join i.sistema s ");
		sql.append("\n WHERE s.coSeqSistema =:coSistema ");

		if (coIgreja != null) {
			params.put("coIgrejaPertence", coIgreja);
			sql.append("\n AND i.coSeqIgreja =:coIgrejaPertence ");
		}

		if (!status.equals("")) {
			params.put("status", status.equals("I") ? true : false);
			sql.append("\n AND m.inativo = :status ");
		}

		sql
				.append(" \n AND (m.igrejaPertence.coSeqIgreja = :coIgreja "
						+ "	OR i.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");

		if ( parametros != null && !parametros.isEmpty()) {
			sql.append("\n AND ");
			montaQueryComParamentros(parametros, params, sql);
		}


		// return membroDao.findByNativeQuery(sql.toString(), params);
		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}
		return consulta.getResultList();
	}

	private void montaQueryComParamentros(List<ParametroPesquisa> parametros,
			Map<String, Object> params, StringBuffer sql) {
		int cont = 0;
		for (ParametroPesquisa pr : parametros) {
			cont++;
			switch (pr.getTpParamentro()) {
			case 1:
				sql.append(" ");
				sql.append("\n ");
				// sql.append( "\n to_date(");
				sql.append("m.");
				sql.append(pr.getOpcao());
				sql.append(" ");
				// sql.append(" , 'dd-mm-yyyy') ");
				sql.append(pr.getOperacao());
				sql.append(" ");
				sql.append("\n to_date('");
				sql.append(DateUtil.getDateStr2(pr.getDtPesquisa()));
				sql.append("', 'dd-mm-yyyy') ");
				// sql.append(" :");
				// sql.append(pr.getOpcao());
				sql.append(" ");
				if (cont < parametros.size()) {
					sql.append(pr.getJuncao());
				}
				sql.append(" ");
				// params.put(pr.getOpcao(), (Date)pr.getDtPesquisa());
				break;
			case 2:
				sql.append("\n ");
				sql.append("UPPER(m.");
				sql.append(pr.getOpcao());
				sql.append(")");
				sql.append(" like ");
				sql.append(" :");
				sql.append(pr.getOpcao());
				sql.append(" ");
				if (cont < parametros.size()) {
					sql.append(pr.getJuncao());
				}
				sql.append(" ");
				String dado = "";
				if (pr.getOperacao().equals(OperacaoPesquisaEnum.CONTENHA.getCodigo())) {
					dado = "%" + pr.getDado().toString().toUpperCase().trim() + "%";
				} else if (pr.getOperacao().equals(OperacaoPesquisaEnum.COMECA_COM.getCodigo())) {
					dado = pr.getDado().toString().toUpperCase().trim() + "%";
				}

				params.put(pr.getOpcao(), dado);
				break;
			case 3:
				sql.append("\n ");
				sql.append("m.");
				sql.append(pr.getOpcao());
				sql.append(" ");
				sql.append(pr.getOperacao());
				sql.append(":");
				sql.append(pr.getOpcao());
				sql.append(" ");
				if (cont < parametros.size()) {
					sql.append(pr.getJuncao());
				}
				sql.append(" ");
				if (pr.getDado() != null) {
					params.put(pr.getOpcao(), Long.valueOf(pr.getDado().toString()));
				} else {
					params.put(pr.getOpcao(), null);
				}
				break;
			default:
				break;
			}
		}
	}

	public List<Membro> buscarAnivarsarianteDia() {
		Map<String, Object> params = new java.util.HashMap<String, Object>();
		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());

		return membroDao.findByNamedParams("buscarAniversariantesDia", params);
	}

	public List<Membro> buscarAnivarsarianteMes() {
		Map<String, Object> params = new java.util.HashMap<String, Object>();
		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		return membroDao.findByNamedParams("buscarAniversariantesMes", params);

	}

	@Override
	public List<MembroVo> buscarAniversariantesDia(boolean contemEmail) {
		Map<String, Object> params = new HashMap<String, Object>();

		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		params.put("coSistema", UsuarioLogado.getCoSistema());

		StringBuffer sql = new StringBuffer();
		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( m ) FROM Membro m ");
		sql.append("\n join m.igrejaPertence i");
		sql.append("\n join i.sistema s");
		sql.append("\n WHERE s.coSeqSistema =:coSistema");
		
		if(contemEmail)
			sql.append("\n AND v.email != '' ");
		
		sql
				.append("\n AND (m.igrejaPertence.coSeqIgreja = :coIgreja OR m.igrejaPertence.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");
		sql.append("\n AND  Extract(Day From dt_nascimento) = Extract(Day From Now()) ");
		sql.append("\n AND  Extract(Month From dt_nascimento) = Extract(Month From Now()) ");
		sql.append(" order by m.nome");

		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}

		return consulta.getResultList();

	}

	@Override
	public List<MembroVo> buscarAniversariantesMes(boolean contemEmail) {
		Map<String, Object> params = new HashMap<String, Object>();

		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		params.put("coSistema", UsuarioLogado.getCoSistema());

		StringBuffer sql = new StringBuffer();
		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( m )  FROM Membro m");
		sql.append("\n join m.igrejaPertence i ");
		sql.append("\n join i.sistema s ");

		sql.append("\n WHERE  Extract(Month From dt_nascimento) = Extract(Month From Now())");

		sql.append("\n AND s.coSeqSistema =:coSistema ");
		if(contemEmail)
			sql.append("\n AND v.email != '' ");

		sql
				.append(" \n AND (i.coSeqIgreja = :coIgreja "
						+ "	OR i.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");

		sql.append(" order by m.dtNascimento");

		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}

		return consulta.getResultList();

	}

	@Override
	public List<MembroVo> buscarAniversariantesMes(int mes, Long coIgreja) {
		Map<String, Object> params = new HashMap<String, Object>();

		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		params.put("coSistema", UsuarioLogado.getCoSistema());
		params.put("inativo", false);

		StringBuffer sql = new StringBuffer();
		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( m )  FROM Membro m");
		sql.append("\n join m.igrejaPertence i ");
		sql.append("\n join i.sistema s ");
		sql.append("\n WHERE m.inativo = :inativo ");

		if (mes == -1) {
			sql.append("\n AND  Extract(Month From dt_nascimento) = Extract(Month From Now())");
		} else {
			sql.append("\n AND extract( month from m.dtNascimento ) = :mes ");
		}

		sql.append("\n AND s.coSeqSistema =:coSistema ");

		if (coIgreja != null) {
			params.put("coIgrejaPertence", coIgreja);
			sql.append("\n AND i.coSeqIgreja =:coIgrejaPertence ");
		}

		sql
				.append(" \n AND (i.coSeqIgreja = :coIgreja "
						+ "	OR i.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");

		params.put("mes", mes);

		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}

		return consulta.getResultList();

	}

	@Override
	public List<MembroVo> buscarAniversariosMembroVisitanteDia() {
		List<MembroVo> listaMembro = buscarAniversariantesDia(true);
		List<MembroVo> listaVisitante = visitanteService.buscarAniversariantesDia(true);

		if (listaMembro == null) {
			listaMembro = new ArrayList<MembroVo>();
		}

		listaMembro.addAll(listaVisitante);

		return listaMembro;
	}

	@Override
	public List<MembroVo> buscarAniversariosMembroVisitanteMes() {
		List<MembroVo> listaMembro = buscarAniversariantesMes(true);
		List<MembroVo> listaVisitante = visitanteService.buscarAniversariantesMes(true);

		if (listaMembro == null) {
			listaMembro = new ArrayList<MembroVo>();
		}

		listaMembro.addAll(listaVisitante);

		return listaMembro;
	}

	@Override
	public Membro buscarMembroPorId(Long coMembro) {
		// Map<String, Object> params = new java.util.HashMap<String, Object>();
		// params.put("coIgreja",UsuarioLogado.getCoIgrejaLocal());
		// params.put("coMembro",coMembro);
		return membroDao.findById(coMembro);
	}

	private List<MembroVo> buscarMembroPorNome(String nome) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		params.put("coSistema", UsuarioLogado.getCoSistema());
		params.put("inativo", false);

		StringBuffer sql = new StringBuffer();

		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( m )  FROM Membro m");
		sql.append("\n inner join m.igrejaPertence i");
		sql.append("\n inner join i.sistema s ");
		sql.append("\n WHERE s.coSeqSistema =:coSistema ");
		sql.append("\n AND m.inativo = :inativo ");

		sql
				.append(" \n AND (i.coSeqIgreja = :coIgreja "
						+ "	OR i.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");
		sql.append("\n AND (UPPER(m.nome) like :nome) ");

		params.put("nome", "%" + nome.toUpperCase() + "%");

		sql.append(" ORDER BY m.nome");

		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}

		return consulta.getResultList();
	}

	@Override
	public List<Membro> buscarMembroPorParametros(Membro membro, String status) {
		Map<String, Object> params = new HashMap<String, Object>();

		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());

		StringBuffer sql = new StringBuffer();

		sql.append("\n SELECT m FROM Membro m ");
		sql.append("\n WHERE m.igrejaPertence.sistema.coSeqSistema =:coSistema ");
		sql
				.append(" \n AND (m.igrejaPertence.coSeqIgreja = :coIgreja "
						+ "	OR m.igrejaPertence.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");
		sql.append("\n AND (UPPER(m.nome) like :nome) ");
		if (membro != null) {
			if (membro.getNome() != null && !membro.getNome().isEmpty()) {
				params.put("nome", "%" + membro.getNome().toUpperCase() + "%");
			} else {
				params.put("nome", "%%");
			}

			if (membro.getMatricula() != null && !membro.getMatricula().isEmpty()) {
				sql.append("\n AND (m.coSeqMembro = :coMembro) ");
				params.put("coMembro", Long.valueOf(membro.getMatricula()));
			}
			if (membro.getDtNascimento() != null) {
				sql.append("\n AND (m.dtNascimento = :dtNascimento)");
				params.put("dtNascimento", membro.getDtNascimento());
			}

			if (status != null && !status.isEmpty()) {
				sql.append("\n AND (m.inativo = :inativo)");
				params.put("inativo", status.equals("I") ? true : false);
			}

		} else {
			params.put("nome", "%%");
		}

		sql.append(" ORDER BY m.nome");
		sql.append(")");

		return membroDao.findByNativeQuery(sql.toString(), params);
	}

	@Override
	public List<MembroVo> buscarMembroVisitantePorParametros(String nome) {
		List<MembroVo> listaMembro = buscarMembroPorNome(nome);
		List<MembroVo> listaVisitante = buscarVisitantePorNome(nome);

		if (listaMembro == null) {
			listaMembro = new ArrayList<MembroVo>();
		}

		listaMembro.addAll(listaVisitante);

		return listaMembro;
	}

	@Override
	public List<Membro> buscarTodosMembroPorFiltros(Membro filtro) {

		if (filtro == null) {
			return new ArrayList<Membro>();
		}

		Criteria crit = membroDao.getCriteria();

		// igual a matricula
		// if(filtro.getCoSeqMembro() != null)
		// crit.add(Restrictions.like("coSeqMembro", filtro.getCoSeqMembro()));
		// igual ao nome
		if (filtro.getNome() != null) {
			crit.add(Restrictions.like("nome", "%" + filtro.getNome() + "%"));
		}

		// igual a data de nascimento
		if (filtro.getDtNascimento() != null) {
			crit.add(Restrictions.eq("dtNascimento", filtro.getDtNascimento()));
		}

		if (filtro.getDtNascimento() != null) {
			crit.add(Restrictions.eq("dtNascimento", filtro.getDtNascimento()));
		}

		return crit.list();
	}

	@Override
	public List<Membro> buscarTodosMembros() {
		return membroDao.findAll();
	}

	@Override
	public List<Membro> buscarTodosMembrosPorUsers() {
		Map<String, Object> params = new java.util.HashMap<String, Object>();
		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		return membroDao.findByNamedParams("buscarTodosMembrosPorUsers", params);
	}

	private List<MembroVo> buscarVisitantePorNome(String nome) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("username", UsuarioLogado.getCoUsuario());
		params.put("coIgreja", UsuarioLogado.getCoIgrejaLocal());
		params.put("coSistema", UsuarioLogado.getCoSistema());
		params.put("inativo", false);

		StringBuffer sql = new StringBuffer();

		sql.append("\n SELECT new br.com.sgi.vo.MembroVo( v )  FROM Visitante v");
		sql.append("\n inner join v.igrejaPertence i");
		sql.append("\n inner join i.sistema s ");
		sql.append("\n WHERE s.coSeqSistema =:coSistema ");
		sql.append("\n AND v.inativo = :inativo ");

		sql
				.append(" \n AND (i.coSeqIgreja = :coIgreja "
						+ "	OR i.coSeqIgreja in(SELECT ui.igreja.coSeqIgreja from UsersIgreja ui WHERE ui.users.username= :username)) ");
		sql.append("\n AND (UPPER(v.nome) like :nome) ");

		params.put("nome", "%" + nome.toUpperCase() + "%");

		sql.append(" ORDER BY v.nome");

		Query consulta = this.entityManager.createQuery(sql.toString());

		for (Entry<String, Object> entry : params.entrySet()) {
			consulta.setParameter(entry.getKey(), entry.getValue());
		}

		return consulta.getResultList();
	}

	@Override
	public void excluir(Long coMembro) {
		membroDao.deleteById(coMembro);

	}

	@Override
	public boolean existeMembroNaIgreja(Long coIgreja) {

		Map<String, Object> params = new HashMap<String, Object>();

		params.put("coIgreja", coIgreja);

		StringBuffer sql = new StringBuffer();
		sql.append("\n SELECT m  FROM Membro m");
		sql.append("\n WHERE m.igrejaPertence.coSeqIgreja = :coIgreja ");
		sql.append("\n AND m.igrejaPertence.sistema.coSeqSistema = :coSistema ");

		List<Membro> listMembro = membroDao.findByNativeQuery(sql.toString(), params);

		if (listMembro == null || listMembro.isEmpty()) {
			return false;
		}

		return true;
	}

	public void salvar(Membro membro) {
		if (membro != null && membro.getCoSeqMembro() == null) {
			membroDao.save(membro);
		}
	}

}
